package edu.mse.camel.client.posterboard.ui.handlers;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;

public class CamelNotificationRecorder  {

	private class CamelCacheAdapter implements Adapter {
		Notifier target;
		CamelNotificationRecorder container;
		List<Adapter> originalAdpaters;
		private int numOriginalAdaptors = 0;
		
		public CamelCacheAdapter (CamelNotificationRecorder container, Notifier target) {
			this.container = container;
			this.target = target;
			
			boolean originalDeliver = target.eDeliver();
			target.eSetDeliver(false);
			originalAdpaters = new ArrayList<Adapter>();
			originalAdpaters.addAll(target.eAdapters());
			numOriginalAdaptors = target.eAdapters().size();
			target.eAdapters().clear();
			target.eAdapters().add(this);
			target.eSetDeliver(originalDeliver);
		}
		
		@Override
		public Notifier getTarget() {
			return target;
		}
	
		@Override
		public boolean isAdapterForType(Object type) {
			return false;
		}
	
		@Override
		public void notifyChanged(Notification notification) {
			for(Adapter adapter: originalAdpaters) {
				NotificationEntry entry = new NotificationEntry(originalAdpaters, notification);
				container.notifications.add(entry);
			}
		}
		
		public void release () {
			boolean originalDeliver = target.eDeliver();
			target.eSetDeliver(false);
			target.eAdapters().remove(this);
			target.eAdapters().addAll(originalAdpaters);
			target.eSetDeliver(originalDeliver);
		}
		
		@Override
		public void setTarget(Notifier newTarget) {
		}

		public int getNumOriginalAdaptors() {
			return numOriginalAdaptors;
		}
	}
	
	private class NotificationEntry {
		public NotificationEntry(List<Adapter> adapters, Notification notification) {
			this.adapters = adapters;
			this.notification = notification;
		}
		public List<Adapter> adapters;
		public Notification notification;
	}
	
	List<CamelCacheAdapter> adapters = new ArrayList<CamelCacheAdapter>();
	List<NotificationEntry> notifications = new ArrayList<NotificationEntry>();
	
	public int install(Notifier notifier) {
		if(! notifier.eAdapters().isEmpty()) {
			CamelCacheAdapter adapter = new CamelCacheAdapter(this, notifier);
			adapters.add(adapter);
			return adapter.getNumOriginalAdaptors();
		}
		return 0;
	}
	
	public void applyAndUninstallForAll() {
		for (CamelCacheAdapter adapter : adapters) {
			adapter.release();
		}
		for(NotificationEntry entry: notifications) {
			for(Adapter adapter: entry.adapters ) {
				adapter.notifyChanged(entry.notification);
			}
		}
	}
}
